#include <stdlib.h>
#include "Arbre.h"
#include "Symbole.h"
#include "SymboleValue.h"

////////////////////////////////////////////////////////////////////////////////
// NoeudSeqInst
////////////////////////////////////////////////////////////////////////////////

NoeudSeqInst::NoeudSeqInst() : tabInst() {
}

////////////////////////////////////////////////////////////////////////////////
Multype* NoeudSeqInst::getValeur() {
  Multype* valeur = NULL;
  for (unsigned int i=0; i<tabInst.size(); i++)
    valeur = tabInst[i]->getValeur();  // on evalue chaque instruction de la séquence
  return valeur; // par convention, resultat = valeur de la derniere instruction
}

////////////////////////////////////////////////////////////////////////////////
void NoeudSeqInst::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Sequence de " << tabInst.size() << " instruction(s)" << endl;
  for (unsigned int i=0; i<tabInst.size(); i++)
    tabInst[i]->afficher(indentation+1); // on affiche les fils en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////
void NoeudSeqInst::ajouteInstruction(Noeud* instruction) {
  tabInst.push_back(instruction);
}

////////////////////////////////////////////////////////////////////////////////
// NoeudAffectation
////////////////////////////////////////////////////////////////////////////////

NoeudAffectation::NoeudAffectation(Noeud* variable, Noeud* expression) {
  this->variable=variable;
  this->expression=expression;
}

////////////////////////////////////////////////////////////////////////////////
Multype* NoeudAffectation::getValeur() {
  Multype* valeur = expression->getValeur(); // on évalue l'expression
  //((SymboleValue*)variable)->setValeur(valeur); // on affecte la variable
  if(typeid(*valeur) == typeid(TypeInt))
	{
		TypeInt* val = dynamic_cast<TypeInt*> (valeur);
		((SymboleValue*)variable)->setValeur(val->getValeur());
	}
  else if(typeid(*valeur) == typeid(TypeString))
	{
		TypeString* val = dynamic_cast<TypeString*> (valeur);
		((SymboleValue*)variable)->setValeur(val->getValeur());
	}
  return valeur; // par convention, une affectation a pour valeur la valeur affectée
}

////////////////////////////////////////////////////////////////////////////////
void NoeudAffectation::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Affectation" << endl;
  variable->afficher(indentation+1);   // on affiche variable et expression
  expression->afficher(indentation+1); // en augmentant l'indentation
}

////////////////////////////////////////////////////////////////////////////////
// NoeudOperateurBinaire
////////////////////////////////////////////////////////////////////////////////

NoeudOperateurBinaire::NoeudOperateurBinaire ( Symbole operateur,
                                               Noeud* operandeGauche,
                                               Noeud* operandeDroit) {
  this->operateur=operateur;
  this->operandeGauche=operandeGauche;
  this->operandeDroit=operandeDroit;
}

////////////////////////////////////////////////////////////////////////////////
Multype* NoeudOperateurBinaire::getValeur() { 
  //Multype* valeur(0);
  Multype* og=operandeGauche->getValeur();
  Multype* od=operandeDroit->getValeur();
  if      (this->operateur=="+") //valeur = og+od; 
  {
  		if( typeid(*og) == typeid(TypeString) and typeid(*od) == typeid(TypeString) )
  		{
  			TypeString* ogs = dynamic_cast<TypeString*> (og);
  			TypeString* ods = dynamic_cast<TypeString*> (od);
  			TypeString* valeur = new TypeString(ogs->getValeur() + ods->getValeur());
  			return valeur;
  		}
  		else if( typeid(*og) == typeid(TypeInt) and typeid(*od) == typeid(TypeInt) )
  		{
  			TypeInt* ogi = dynamic_cast<TypeInt*> (og);
  			TypeInt* odi = dynamic_cast<TypeInt*> (od);
  			TypeInt* valeur = new TypeInt(ogi->getValeur() + odi->getValeur());
  			return valeur;
  		}
  		else
  		{
  			cout << "Erreur pendant l'interpretation : ajout de 2 types différents" << endl;
	  		exit(0); // plus tard on levera une exception
  		}
  }
  else if (this->operateur=="-")//valeur = og-od;
  {
  	if( typeid(*og) == typeid(TypeInt) and typeid(*od) == typeid(TypeInt) )
  		{
  			TypeInt* ogi = dynamic_cast<TypeInt*> (og);
  			TypeInt* odi = dynamic_cast<TypeInt*> (od);
  			TypeInt* valeur = new TypeInt(ogi->getValeur() - odi->getValeur());
  			return valeur;
  		}
  		else
  		{
  			cout << "Erreur pendant l'interpretation : soustraction avec un autre type qu'Entier" << endl;
	  		exit(0); // plus tard on levera une exception
  		}
  	}
  else if (this->operateur=="*") //valeur = og*od;
  {
  	if( typeid(*og) == typeid(TypeInt) and typeid(*od) == typeid(TypeInt) )
  		{
  			TypeInt* ogi = dynamic_cast<TypeInt*> (og);
  			TypeInt* odi = dynamic_cast<TypeInt*> (od);
  			TypeInt* valeur = new TypeInt(odi->getValeur() * ogi->getValeur());
  			return valeur;
  		}
  		else
  		{
  			cout << "Erreur pendant l'interpretation : multiplication avec un autre type qu'Entier" << endl;
	  		exit(0); // plus tard on levera une exception
  		}
  }
  else if (this->operateur=="/") // this->operateur=="/"
  {
	if( typeid(*og) == typeid(TypeInt) and typeid(*od) == typeid(TypeInt) )
  	{
  		TypeInt* ogi = dynamic_cast<TypeInt*> (og);
  		TypeInt* odi = dynamic_cast<TypeInt*> (od);
  			
  		if (odi->getValeur()!=0)
		{
			TypeInt* valeur = new TypeInt(ogi->getValeur() * odi->getValeur());
			return valeur;
		}
  		else
  		{
	  		cout << "Erreur pendant l'interpretation : division par zero" << endl;
	  		exit(0); // plus tard on levera une exception
	  	}
	  }
	  else 
	  {
	  	cout << "Erreur pendant l'interpretation : division avec des Type différents de Entier" << endl;
	  	exit(0); // plus tard on levera une exception
  	}
  }
  else if (this->operateur=="<") // this->operateur=="/"
  {
	if( typeid(*og) == typeid(TypeInt) and typeid(*od) == typeid(TypeInt) )
  	{
  		TypeInt* ogi = dynamic_cast<TypeInt*> (og);
  		TypeInt* odi = dynamic_cast<TypeInt*> (od);
  		
  		if (ogi->getValeur()< odi->getValeur())
		{
			
			TypeInt* valeur = new TypeInt(1);
			
			return valeur;
		}
  		else
  		{
	  		TypeInt* valeur = new TypeInt(0);
			return valeur;
	  	}
	  }
	 else
	{
	  	cout << "Erreur pendant l'interpretation : condition expression booléenne avec un type autre que entier" << endl;
	  	exit(0); // plus tard on levera une exception
  	}
  }
  else if (this->operateur==">") // this->operateur=="/"
  {
	if( typeid(*og) == typeid(TypeInt) and typeid(*od) == typeid(TypeInt) )
  	{
  		TypeInt* ogi = dynamic_cast<TypeInt*> (og);
  		TypeInt* odi = dynamic_cast<TypeInt*> (od);
  			
  		if (ogi->getValeur()> odi->getValeur())
		{
			TypeInt* valeur = new TypeInt(1);
			return valeur;
		}
  		else
  		{
	  		TypeInt* valeur = new TypeInt(0);
			return valeur;
	  	}
	  }
	 else
	{
	  	cout << "Erreur pendant l'interpretation : condition expression booléenne avec un type autre que entier" << endl;
	  	exit(0); // plus tard on levera une exception
  	}
  }
  
  
  	
  return new TypeInt(0);
  
}

////////////////////////////////////////////////////////////////////////////////
void NoeudOperateurBinaire::afficher(unsigned short indentation) {
  Noeud::afficher(indentation);
  cout << "Noeud - Operateur Binaire \"" << this->operateur.getChaine() << "\" applique a : " << endl;
  operandeGauche->afficher(indentation+1);  // on affiche fils gauche et fils droit
  operandeDroit->afficher(indentation+1);   // en augmentant l'indentation
}



////////////////////////////////////////////////////////////////////////////////
// NoeudInstTq
////////////////////////////////////////////////////////////////////////////////

NoeudInstTq::NoeudInstTq(Noeud* expBool, Noeud* seqInst) {
	this->expBool = expBool;
	this->seqInst = dynamic_cast<NoeudSeqInst*> (seqInst);
	
}

////////////////////////////////////////////////////////////////////////////////

Multype* NoeudInstTq::getValeur() {
	Multype* valeur = NULL;
	Multype* og=expBool->getValeur();
	if( typeid(*og) == typeid(TypeInt) )
	{
		
		TypeInt* ogi = dynamic_cast<TypeInt*> (og);
		while (ogi->getValeur() )
		{
			valeur = seqInst->getValeur();
			og=expBool->getValeur();
			ogi = dynamic_cast<TypeInt*> (og);
			
		}
	}
	else
	{
	  	cout << "Erreur pendant l'interpretation : condition expression booléenne avec un type autre que entier" << endl;
	  	exit(0); // plus tard on levera une exception
  	}
		
	return valeur;
}

////////////////////////////////////////////////////////////////////////////////


void NoeudInstTq::afficher(unsigned short indentation)
{
	Noeud::afficher(indentation);
	cout << "Noeud - Tantque";
	expBool->afficher();
	cout << "Faire";
	seqInst->afficher(indentation+1);
	cout << "FinTantque " << endl;
	
}
////////////////////////////////////////////////////////////////////////////////
// NoeudInstRepeter
////////////////////////////////////////////////////////////////////////////////

NoeudInstRepeter::NoeudInstRepeter(Noeud* expBool, Noeud* seqInst) {
	this->expBool = expBool;
	this->seqInst = dynamic_cast<NoeudSeqInst*> (seqInst);
	
}

void NoeudInstRepeter::afficher(unsigned short indentation)
{
	Noeud::afficher(indentation);
	cout << "Noeud - Répeter" << endl;
	seqInst->afficher(indentation+1);
	cout << "jusqu'à " << endl;
	expBool->afficher();
}

////////////////////////////////////////////////////////////////////////////////

Multype* NoeudInstRepeter::getValeur()
{
	Multype* valeur = NULL;
	Multype* og=expBool->getValeur();
	if( typeid(*og) == typeid(TypeInt) )
	{
		
		TypeInt* ogi = dynamic_cast<TypeInt*> (og);
		do
		{
			valeur = seqInst->getValeur();
			og=expBool->getValeur();
			ogi = dynamic_cast<TypeInt*> (og);
			
		}while (ogi->getValeur() );
	}
	else
	{
	  	cout << "Erreur pendant l'interpretation : condition expression booléenne avec un type autre que entier" << endl;
	  	exit(0); // plus tard on levera une exception
  	}
		
	return valeur;
}

////////////////////////////////////////////////////////////////////////////////

void NoeudInstPour::afficher(unsigned short indentation)
{
	Noeud::afficher(indentation);
	cout << "Noeud - Pour" << endl;
	affectation->afficher(indentation +1);
	expBool->afficher(indentation+1);
	affectationPour->afficher(indentation+1);
	cout << "faire" << endl;
	seqInst->afficher(indentation+1);
	cout << "finPour" << endl;
	expBool->afficher();
}

////////////////////////////////////////////////////////////////////////////////


NoeudInstPour::NoeudInstPour(Noeud* expBool, Noeud* seqInst, Noeud* aff, Noeud* aff2)
{
	this->expBool = expBool;
	this->seqInst = dynamic_cast<NoeudSeqInst*> (seqInst);
	this->affectation = aff;
	this->affectationPour = aff2;
}

////////////////////////////////////////////////////////////////////////////////

Multype* NoeudInstPour::getValeur()
{
	Multype* valeur = NULL;
	Multype* og=affectation->getValeur();
	
	if( typeid(*og) == typeid(TypeInt) )
	{
		
		TypeInt* ogi = dynamic_cast<TypeInt*> (og);
		do
		{
			valeur = seqInst->getValeur();
			valeur = affectationPour->getValeur();
			og=expBool->getValeur();
			ogi = dynamic_cast<TypeInt*> (og);
			
		}while (ogi->getValeur() );
	}
	else
	{
	  	cout << "Erreur pendant l'interpretation : condition expression booléenne avec un type autre que entier" << endl;
	  	exit(0); // plus tard on levera une exception
  	}
		
	return valeur;
}

////////////////////////////////////////////////////////////////////////////////

NoeudInstLire::NoeudInstLire(Noeud* var)
{
	this->variable = var; 
}


Multype* NoeudInstLire::getValeur()
{
	SymboleValue* s = dynamic_cast<SymboleValue*> (variable);
	Multype* val=variable->getValeur();
	
	if( typeid(*val) == typeid(TypeInt) )
	{
		
		int a;
		cout << "Entrez la variable entière : " << endl;
		cin >> a;
		cin.ignore(256, '\n'); 
		s->setValeur(a);
		return s->getValeur();
	}
	else
	{
		string a;
		cout << "Entrez la variable : " << endl;
		getline(cin, a);
		s->setValeur(a);
		return s->getValeur();
	}
	return new TypeInt(0);
}

void NoeudInstLire::afficher(unsigned short indentation)
{
	Noeud::afficher(indentation);
	cout << "Noeud - Lire" << endl;
	cout << "Lire :" << endl;
	variable->afficher(indentation +1);
}
////////////////////////////////////////////////////////////////////////////////////////

NoeudInstEcrire::NoeudInstEcrire(Noeud* var)
{
	this->variable = var; 
}


Multype* NoeudInstEcrire::getValeur()
{
	Multype* val=variable->getValeur();
	
	if( typeid(*val) == typeid(TypeInt) )
	{
		TypeInt* i = dynamic_cast<TypeInt*> (val);
		cout << i->getValeur() << endl;
		return val;
	}
	else if( typeid(*val) == typeid(TypeString) )
	{
		TypeString* i = dynamic_cast<TypeString*> (val);
		cout << i->getValeur()<< endl;
		return val;
	}
	else
	{
		//cas d'une expression
	}
	return new TypeInt(0);
}

void NoeudInstEcrire::afficher(unsigned short indentation)
{
	Noeud::afficher(indentation);
	cout << "Noeud - Ecrire" << endl;
	cout << "Ecrire :" << endl;
	variable->afficher(indentation +1);
}

////////////////////////////////////////////////////////////////////////////////////////

NoeudInstSi::NoeudInstSi(Noeud* exp, Noeud* inst1, Noeud*  inst2)
{
	this->expBool = exp;
	this->instGauche = dynamic_cast<NoeudSeqInst*> (inst1);
	this->instDroit = inst2;
}


Multype* NoeudInstSi::getValeur()
{
	Multype* valeur = NULL;
	Multype* exp=expBool->getValeur();
	if( typeid(*exp) == typeid(TypeInt) )
	{
		
		TypeInt* expInt = dynamic_cast<TypeInt*> (exp);
		if (expInt->getValeur() )
		{
			return instGauche->getValeur();
		}
		else
		{
			if(typeid(*instDroit) == typeid(NoeudInstSi) )
			{
				NoeudInstSi* noeud = dynamic_cast<NoeudInstSi*> (instDroit);
				return noeud->getValeur();
			}
			else if(instDroit != NULL)
			{
				NoeudSeqInst* noeud = dynamic_cast<NoeudSeqInst*> (instDroit);
				return  noeud->getValeur();
			}
			return new TypeInt(0);
		}
	}
	else
	{
	  	cout << "Erreur pendant l'interpretation : condition expression booléenne avec un type autre que entier" << endl;
	  	exit(0); // plus tard on levera une exception
  	}
		
	return valeur;
}

void NoeudInstSi::afficher(unsigned short indentation)
{
	Noeud::afficher(indentation);
	cout << "Noeud - Si"<< endl;
	expBool->afficher(indentation++);
	cout << "Alors" << endl;
	instGauche->afficher(indentation++);
	if(instDroit != NULL)
	{
		cout << "Sinon" << endl;
		if(typeid(*instDroit) == typeid(NoeudInstSi) )
		{
			NoeudInstSi* noeud = dynamic_cast<NoeudInstSi*> (instDroit);
			noeud->afficher();
		}
		else
		{
			NoeudSeqInst* noeud = dynamic_cast<NoeudSeqInst*> (instDroit);
			noeud->afficher();
		}
	}
	cout << "Finsi"<< endl;
	
}
